<template>
  <form class="edoovo-form">
    <slot></slot>
  </form>
</template>
<script>
/**
 * form支持的参数
 * @prop { model } Object 如果需要校验部分，一定要添加model属性
 * @prop { rules } Object 绑定在form的校验规则，通过prop字段进行绑定子属性
 * @prop { labelSuffix } String 表单域标签的后缀
 * @prop { disabled } Boolean 是否禁用表单所有元素
 * @prop { validateOnRuleChange } Boolean 是否在 rules 属性改变后立即触发一次验证
 * @prop { showMessage } Boolean 是否显示错误信息
 */
export default {
  name: 'EdoovoForm',
  componentName: 'EdoovoForm',
  provide() {
    return {
      edoovoForm: this
    };
  },
  props: {
    model: Object,
    rules: Object,
    labelSuffix: {
      type: String,
      default: ''
    },
    disabled: Boolean,
    validateOnRuleChange: {
      type: Boolean,
      default: true
    },
    showMessage: {
      type: Boolean,
      default: true
    }
  },
  watch: {
    rules() {
      // remove then add event listeners on form-item after form rules change
      this.fields.forEach(field => {
        field.removeValidateEvents();
        field.addValidateEvents();
      });
      if (this.validateOnRuleChange) {
        this.validate(() => {});
      }
    }
  },
  computed: {},
  data() {
    return {
      fields: []
    };
  },
  /**
   * 监听来自item子组件注册的校验信息
   * @returns { void }
   */
  created() {
    this.$on('edoovo.form.addField', field => {
      if (field) {
        this.fields.push(field);
      }
    });
    /* istanbul ignore next */
    this.$on('edoovo.form.removeField', field => {
      if (field.prop) {
        this.fields.splice(this.fields.indexOf(field), 1);
      }
    });
  },
  methods: {
    resetFields() {
      if (!this.model) {
        console.warn('[Edoovo Warn][Form]model is required for resetFields to work.');
        return;
      }
      this.fields.forEach(field => {
        field.resetField();
      });
    },
    clearValidate(props = []) {
      const fields = props.length
        ? typeof props === 'string'
          ? this.fields.filter(field => props === field.prop)
          : this.fields.filter(field => props.indexOf(field.prop) > -1)
        : this.fields;
      fields.forEach(field => {
        field.clearValidate();
      });
    },
    validate(callback) {
      if (!this.model) {
        console.warn('[Edoovo Warn][Form]model is required for validate to work!');
        return;
      }

      let promise;
      // if no callback, return promise
      if (typeof callback !== 'function' && window.Promise) {
        promise = new window.Promise((resolve, reject) => {
          callback = function(valid) {
            valid ? resolve(valid) : reject(valid);
          };
        });
      }

      let valid = true;
      let count = 0;
      // 如果需要验证的fields为空，调用验证时立刻返回callback
      if (this.fields.length === 0 && callback) {
        callback(true);
      }
      let invalidFields = {};
      this.fields.forEach(field => {
        field.validate('', (message, field) => {
          if (message) {
            valid = false;
          }
          invalidFields = Object.assign({}, invalidFields, field);
          if (typeof callback === 'function' && ++count === this.fields.length) {
            callback(valid, invalidFields);
          }
        });
      });

      if (promise) {
        // eslint-disable-next-line consistent-return
        return promise;
      }
    },
    validateField(props, cb) {
      props = [].concat(props);
      const fields = this.fields.filter(field => props.indexOf(field.prop) !== -1);
      if (!fields.length) {
        console.warn('[Edoovo Warn]please pass correct props!');
        return;
      }

      fields.forEach(field => {
        field.validate('', cb);
      });
    }
  }
};
</script>
